package com.comba.nutz.boot.starter.impl;

import com.comba.nutz.boot.starter.dao.SpringNutDao;
import org.nutz.dao.Chain;
import org.nutz.dao.Condition;
import org.nutz.dao.Sqls;
import org.nutz.dao.pager.Pager;
import org.nutz.dao.sql.Sql;
import org.nutz.service.IdNameEntityService;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.List;
import java.util.Map;

/**
 * @author zhangjp
 * @date 2016/8/12.
 */
public class BaseServiceImpl<T> extends IdNameEntityService<T> {

    @Autowired
    public void setDao(SpringNutDao dao) {
        super.setDao(dao);
    }

    @Override
    public SpringNutDao dao() {
        return (SpringNutDao) super.dao();
    }

    /**
     * 根据ID和正则表达式关联查询
     *
     * @param name 实体ID
     * @param regex 正则表达式
     * @return
     */
    public T fetchByJoin(String name, String regex) {
        return dao().fetchByJoin(getEntityClass(), regex, name);
    }

    /**
     * 根据ID和正则表达式关联查询
     *
     * @param id 实体ID
     * @param regex 正则表达式
     * @return
     */
    public T fetchByJoin(long id, String regex) {
        return dao().fetchByJoin(getEntityClass(), regex, id);
    }

    /**
     * 根据条件和正则表达式关联查询
     *
     * @param cnd 查询条件
     * @param regex 正则表达式
     * @return
     */
    public T fetchByJoin(Condition cnd, String regex) {
        return dao().fetchByJoin(getEntityClass(), regex, cnd);
    }

    /**
     * 根据条件和正则表达式关联查询多条
     *
     * @param cnd 查询条件
     * @param regex 正则表达式
     * @return
     */
    public List<T> queryByJoin(Condition cnd, String regex) {
        return dao().queryByJoin(getEntityClass(), regex, cnd);
    }

    /**
     * 根据条件分页查询
     * @param cnd 查询条件
     * @param pager 分页
     * @return 查询结果
     */
    public List<T> queryByPage(Condition cnd, Pager pager) {
        List<T> result = query(cnd, pager);
        if(pager != null) {
            pager.setRecordCount(count(cnd));
        }

        return result;
    }

    /**
     * 根据条件分页查询
     * @param filters 查询条件   where key=value and key=value
     * @param pager 分页
     * @return
     */
    public List<T> queryByPage(Map<String, Object> filters, Pager pager) {
        return dao().query(getEntityClass(), filters, pager);
    }


    /**
     * 根据条件和正则表达式分页关联查询
     *
     * @param cnd 查询条件
     * @param regex 正则表达式
     * @param pager 分页
     * @return 查询结果
     */
    public List<T> queryByJoin(Condition cnd, String regex, Pager pager) {
        List<T> result = dao().queryByJoin(getEntityClass(), regex, cnd, pager);
        if(pager != null) {
            pager.setRecordCount(dao().countByJoin(getEntityClass(), regex, cnd));
        }

        return result;
    }

   /**
    * 查询一组对象。你可以为这次查询设定条件
    * 
    */
    public List<T> query(Condition cnd) {
        return query(cnd, null);
    }

    /**
     * 查询一组对象。你可以为这次查询设定条件
     * @param filters 查询条件   where key=value and key=value
     * @return
     */
    public List<T> query(Map<String, Object> filters) {
        return dao().query(getEntityClass(), filters);
    }

    public List<T> queryBySqlKey(String sqlKey, Map<String, Object> params, Pager pager) {
        Sql sql = dao().sqls().create(sqlKey);

        return queryBySql(sql, params, pager);
    }

    public List<T> queryBySqlKey(String sqlKey, Condition condition, Pager pager) {
        Sql sql = dao().sqls().create(sqlKey);

        return queryBySql(sql, condition, pager);
    }

    public List<T> queryBySql(String sql, Map<String, Object> params, Pager pager) {
        Sql sql1 = Sqls.create(sql);

        return queryBySql(sql1, params, pager);
    }

    public List<T> queryBySql(Sql sql,  Map<String, Object> params, Pager pager) {
        sql.setCallback(Sqls.callback.entities());
        sql.setEntity(getEntity());

        for(Map.Entry param : params.entrySet()) {
            if(param.getKey().toString().contains("$")) {
                sql.setVar(param.getKey().toString().substring(1), param.getValue());
            } else {
                sql.setParam(param.getKey().toString(), param.getValue());
            }
        }
        if (pager != null) {
            pager.setRecordCount(queryCount(sql, params));
            sql.setPager(pager);
        }

        dao().execute(sql);

        return sql.getList(getEntityClass());
    }

    public List<T> queryBySql(Sql sql,  Condition condition, Pager pager) {
        sql.setCallback(Sqls.callback.entities());
        sql.setEntity(getEntity());
        sql.setCondition(condition);

        if (pager != null) {
            pager.setRecordCount(queryCount(sql, condition));
            sql.setPager(pager);
        }

        dao().execute(sql);

        return sql.getList(getEntityClass());
    }

    public int queryCount(Sql sql, Map<String, Object> params) {
        Sql sql2 = Sqls.fetchInt("select count(1) from ("
                + sql.getSourceSql()
                + ") as _nutz_tmp_"
                + System.currentTimeMillis());

        for(Map.Entry param : params.entrySet()) {
            if(param.getKey().toString().contains("$")) {
                sql2.setVar(param.getKey().toString().substring(1), param.getValue());
            } else {
                sql2.setParam(param.getKey().toString(), param.getValue());
            }
        }

        dao().execute(sql2);
        return sql2.getInt();
    }

    public int queryCount(Sql sql, Condition condition) {
        Sql sql2 = Sqls.fetchInt("select count(1) from ("
                + sql.getSourceSql()
                + ") as _nutz_tmp_"
                + System.currentTimeMillis());

        sql2.setCondition(condition);

        dao().execute(sql2);
        return sql2.getInt();
    }

    /**
     * 更新一个对象，并且忽略所有 null 字段。
     * 注意: 基本数据类型都是不可能为null的,这些字段肯定会更新
     * @param obj 要被更新的对象 
     * 注意： 如果是集合，数组或者 Map，所有的对象必须类型相同，否则可能会出错
     * @return 返回实际被更新的记录条数，一般的情况下，如果是单一Pojo,更新成功，返回 1，否则，返回 0
     */
    public int updateIgnoreNull(T obj) {
        return dao().updateIgnoreNull(obj);
    }

    /**
     * 将一个对象插入到一个数据源。 
	 *
	 * 声明了 '@Id'的字段会在插入数据库时被忽略，因为数据库会自动为其设值。如果想手动设置，请设置 '@Id(auto=false)'
	 *
     * @param obj 对象
     * @return 插入后的对象
     */
    public T insert(T obj) {
        return dao().insert(obj);
    }
    
    /**
     * 更新对象一部分字段
     * @param obj 对象
     * @param regex 正则表达式描述要被更新的字段
     * @return 返回实际被更新的记录条数，一般的情况下，如果更新成功，返回 1，否则，返回 0
     */
    public int update(T obj, String regex) {
        return dao().update(obj, regex);
    }

    /**
     * 关联更新
     *
     * @param regex 正则表达式
     * @param chain 更新字段
     * @param condition 条件
     * @return 返回实际被更新的记录条数，一般的情况下，如果更新成功，返回 1，否则，返回 0
     */
    public int updateRelation(String regex, Chain chain, Condition condition) {
        return dao().updateRelation(getEntityClass(), regex, chain, condition);
    }

    /**
     * 关联更新
     *
     * @param chain 更新字段
     * @param condition 条件
     * @return 返回实际被更新的记录条数，一般的情况下，如果更新成功，返回 1，否则，返回 0
     */
    public int updateRelation(Chain chain, Condition condition) {
        return updateRelation(null, chain, condition);
    }

    /**
     * 批量删除，支持集合
     * @param obj 要被删除的对象
     * @return
     */
    public int delete(T obj) {
        return dao().delete(obj);
    }

    /**
     * 将对象删除的同时，也将符合一个正则表达式的所有关联字段关联的对象统统删除
     * @param obj 数据对象
     * @param regex 正则表达式，描述了什么样的关联字段将被关注。如果为 null，则表示全部的关联字段都会被删除
     * @return 被影响的记录行数
     */
    public int deleteWidth(T obj, String regex) {
        return dao().deleteWith(obj, regex);
    }
}
